package com.fishingwithme.domain.user;

import com.fishingwithme.domain.credit.CreditService;
import com.fishingwithme.infrastructure.WeChatUserInfo;
import com.fishingwithme.infrastructure.dtos.CodeVerifyDto;
import com.fishingwithme.infrastructure.dtos.UserInfoDto;
import com.fishingwithme.infrastructure.dtos.UserPageDto;
import com.fishingwithme.infrastructure.mapper.CodeVerifyMapper;
import com.fishingwithme.infrastructure.mapper.SpotUserMapper;
import com.fishingwithme.infrastructure.cache.CacheService;
import com.fishingwithme.infrastructure.utils.CommonUtils;
import com.fishingwithme.infrastructure.utils.EmailSenderFactory;
import com.fishingwithme.infrastructure.utils.IdGenerator;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.mail.SimpleEmail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;

import java.util.UUID;
import java.util.List;


@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private SpotUserMapper spotUserMapper;

    @Autowired
    private CodeVerifyMapper codeVerifyMapper;

    @Autowired
    private EmailSenderFactory emailFactory;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private CreditService creditService;

    @Value("${spring.mail.username}")
    private String sendEmailAddress;

    @Override
    public IPage<UserPageDto> getUserPage(int pageNum, int pageSize) {
        Page<UserPageDto> page = new Page<>(pageNum, pageSize);
        return spotUserMapper.selectUserPage(page);
    }

    @Transactional
    public SpotUser findOrCreateUser(WeChatUserInfo weChatUserInfo) {
        // 先从缓存获取用户
        SpotUser user = cacheService.getUserByOpenId(weChatUserInfo.getOpenId());

        if (user == null) {
            // 缓存未命中，从数据库获取
            user = spotUserMapper.findByOpenId(weChatUserInfo.getOpenId());

            if (user == null) {
                // 创建新用户
                String uuid = UUID.randomUUID().toString();

                user = new SpotUser();
                user.setOpenId(weChatUserInfo.getOpenId());
                user.setUnionId(uuid);
                user.setUsername(uuid);
                user.setNickname(
                        StringUtils.hasText(weChatUserInfo.getNickName()) ? weChatUserInfo.getNickName() : "钓友");
                // user.setUsername(StringUtils.hasText(weChatUserInfo.getUsername()) ?
                // weChatUserInfo.getUsername() : CommonUtils.generateRandomString(12, 1));
                user.setAvatarUrl("null".equals(weChatUserInfo.getAvatarUrl()) ? null : weChatUserInfo.getAvatarUrl());
                user.setGender(weChatUserInfo.getGender());
                user.setCity(weChatUserInfo.getCity());
                user.setProvince(weChatUserInfo.getProvince());
                user.setCountry(weChatUserInfo.getCountry());
                user.setAdmin(false); // 默认不是管理员
                // 生成随机用户名
                user.setUserId(idGenerator.nextId());
                user.setCreatedBy(user.getUserId());
                user.setUpdatedBy(user.getUserId());
                Date date = new Date();
                user.setUpdatedAt(date);
                user.setRegisterTime(date);
                user.setCreatedAt(date);
                // 保存用户
                spotUserMapper.insertUser(user);

                // TODO: 初始化用户信息。
                creditService.addUserRecord(user.getUserId());
            }
            // 添加到缓存
            cacheService.cacheUser(user);

        }
        return user;
    }

    public SpotUser loadUserByOpenId(String openId) {
        // 先从缓存获取用户
        SpotUser user = cacheService.getUserByOpenId(openId);

        if (user == null) {
            // 缓存未命中，从数据库获取
            user = spotUserMapper.findByOpenId(openId);
            if (user != null) {
                // 添加到缓存
                cacheService.cacheUser(user);
            }
        }
        return user;
    }

    @Override
    public UserInfoDto loadUserByUserId() {
        SpotUser spotUser = spotUserMapper.findByUserId(CommonUtils.getUserId());
        if (spotUser == null) {
            return null;
        }
        return UserInfoDto.from(spotUser);
    }

    @Override
    public SpotUser loadUserByUserId(Long userId) {
        SpotUser spotUser = cacheService.getUserByUserId(userId);
        if (spotUser == null) {
            spotUser = spotUserMapper.findByUserId(userId);
            if (spotUser != null) {
                cacheService.cacheUser(spotUser);
            } else {
                throw new RuntimeException("用户不存在");
            }
        }
        return spotUser;
    }

    @Override
    public Boolean sendingEmail(String email) {

        try {
            Integer verifyCode = CommonUtils.generateRandomNumber();
            SimpleEmail simpleEmail = emailFactory.createSimpleEmail();
            simpleEmail.setFrom(sendEmailAddress);
            simpleEmail.setSubject("圣刚钓鱼邮箱验证码:" + verifyCode);
            simpleEmail.setSentDate(new Date());
            simpleEmail.setMsg("您的验证码是：" + verifyCode);
            simpleEmail.addTo(email);
            simpleEmail.send();

            VerifyCode code = new VerifyCode();
            code.setType(CommonUtils.CODE_VERIFY_EMAIL);
            code.setCode(verifyCode);
            code.setUserId(CommonUtils.getUserId());
            code.setExpireTime(new Date(System.currentTimeMillis() + 1000 * 60 * 5));

            codeVerifyMapper.insert(code);
            return Boolean.TRUE;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Transactional
    @Override
    public CodeVerifyDto saveUserEmail(CodeVerifyDto verifyDto) {
        CodeVerifyDto response = verifyEmailCode(verifyDto.getCode());
        if (response.getIsValid()) {
            spotUserMapper.updateUserEmail(CommonUtils.getUserId(), verifyDto.getEmail());
        }
        return response;
    }

    @Transactional
    @Override
    public String saveUserNickName(String nickname) {
        spotUserMapper.updateUserNickname(CommonUtils.getUserId(), nickname);
        return nickname;
    }

    @Transactional
    @Override
    public String saveUserAvatar(String avatar) {
        spotUserMapper.updateUserAvatar(CommonUtils.getUserId(), avatar);
        return avatar;
    }

    @Override
    @Transactional
    public Integer saveUserGender(Integer gender) {
        spotUserMapper.updateUserGender(CommonUtils.getUserId(), gender);
        return gender;
    }

    @Override
    public boolean logout() {
        Long userId = CommonUtils.getUserId();
        try {
            cacheService.deleteUser(userId);
            return true;
        } catch (Exception e) {
            log.error("删除用户缓存失败", e);
            return false;
        }
    }

    @Transactional
    @Override
    public Boolean cancel(Boolean status) {
        Long userId = CommonUtils.getUserId();
        log.info("注销用户:{}", userId);
        cacheService.deleteUser(userId);
        spotUserMapper.disableUser(userId,status);
        return true;
    }

    @Override
    public CodeVerifyDto verifyEmailCode(Integer code) {
        VerifyCode verifyCode = codeVerifyMapper.selectByUserIdAndType(CommonUtils.getUserId(),
                CommonUtils.CODE_VERIFY_EMAIL);
        if (!code.equals(verifyCode.getCode()) || verifyCode.getExpireTime().before(new Date())) {
            return new CodeVerifyDto(verifyCode.getCode(), Boolean.FALSE, null);
        } else {
            return new CodeVerifyDto(verifyCode.getCode(), Boolean.TRUE, null);
        }

    }

    @Override
    public SpotUser loadUserByName(String username) {
        SpotUser user = cacheService.getUserByUsername(username);
        if(user == null) {
            user = spotUserMapper.findByUsername(username);
        }
        if(user == null) {
            throw new UsernameNotFoundException("User Not Found with username: " + username);
        }
        return user;
        
    }

    @Override
    public List<UserPageDto> searchUsersByName(String username) {
        return spotUserMapper.searchUsersByName(username);
    }

    @Override
    @Transactional
    public Boolean switchAdmin(Long userId, Boolean isAdmin) {
        spotUserMapper.updateAdminStatus(userId, isAdmin);
        return Boolean.TRUE;
    }

    @Override
    public Boolean cancel(Boolean status, Long id) {
        log.info("注销用户:{}", id);
        cacheService.deleteUser(id);
        spotUserMapper.disableUser(id,status);
        return true;
    }
}
